home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkEvent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-21  |  48.2 KB  |  1,752 lines

  1. /* 
  2.  * tkEvent.c --
  3.  *
  4.  *    This file provides basic event-managing facilities,
  5.  *    whereby procedure callbacks may be attached to
  6.  *    certain events.
  7.  *
  8.  * Copyright 1990-1992 Regents of the University of California.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkEvent.c,v 1.60 92/08/21 16:15:57 ouster Exp $ SPRITE (Berkeley)";
  20. #endif
  21.  
  22. #include "tkConfig.h"
  23. #include "tkInt.h"
  24. #include <errno.h>
  25. #include <signal.h>
  26.  
  27. /*
  28.  * For each timer callback that's pending, there is one record
  29.  * of the following type, chained together in a list sorted by
  30.  * time (earliest event first).
  31.  */
  32.  
  33. typedef struct TimerEvent {
  34.     struct timeval time;    /* When timer is to fire. */
  35.     void (*proc)  _ANSI_ARGS_((ClientData clientData));
  36.                 /* Procedure to call. */
  37.     ClientData clientData;    /* Argument to pass to proc. */
  38.     Tk_TimerToken token;    /* Identifies event so it can be
  39.                  * deleted. */
  40.     struct TimerEvent *nextPtr;    /* Next event in queue, or NULL for
  41.                  * end of queue. */
  42. } TimerEvent;
  43.  
  44. static TimerEvent *timerQueue;    /* First event in queue. */
  45.  
  46. /*
  47.  * The information below is used to provide read, write, and
  48.  * exception masks to select during calls to Tk_DoOneEvent.
  49.  */
  50.  
  51. static int readCount;        /* Number of files for which we */
  52. static int writeCount;        /* care about each event type. */
  53. static int exceptCount;
  54. #define MASK_SIZE ((OPEN_MAX+(8*sizeof(int))-1)/(8*sizeof(int)))
  55. static int masks[3*MASK_SIZE];    /* Integer array containing official
  56.                  * copies of the three sets of
  57.                  * masks. */
  58. static int ready[3*MASK_SIZE];    /* Temporary copy of masks, passed
  59.                  * to select and modified by kernel
  60.                  * to indicate which files are
  61.                  * actually ready. */
  62. static int *readPtr;        /* Pointers to the portions of */
  63. static int *writePtr;        /* *readyPtr for reading, writing, */
  64. static int *exceptPtr;        /* and excepting.  Will be NULL if
  65.                  * corresponding count (e.g. readCount
  66.                  * is zero. */
  67. static int numFds = 0;        /* Number of valid bits in mask
  68.                  * arrays (this value is passed
  69.                  * to select). */
  70.  
  71. /*
  72.  * For each file registered in a call to Tk_CreateFileHandler,
  73.  * and for each display that's currently active, there is one
  74.  * record of the following type.  All of these records are
  75.  * chained together into a single list.
  76.  */
  77.  
  78. typedef struct FileEvent {
  79.     int fd;            /* Descriptor number for this file. */
  80.     int *readPtr;        /* Pointer to word in ready array
  81.                  * for this file's read mask bit. */
  82.     int *writePtr;        /* Same for write mask bit. */
  83.     int *exceptPtr;        /* Same for except mask bit. */
  84.     int mask;            /* Value to AND with mask word to
  85.                  * select just this file's bit. */
  86.     void (*proc)  _ANSI_ARGS_((ClientData clientData, int mask));
  87.                 /* Procedure to call.  NULL means
  88.                  * this is a display. */
  89.     ClientData clientData;    /* Argument to pass to proc.  For
  90.                  * displays, this is a (Display *). */
  91.     struct FileEvent *nextPtr;    /* Next in list of all files we
  92.                  * care about (NULL for end of
  93.                  * list). */
  94. } FileEvent;
  95.  
  96. static FileEvent *fileList;    /* List of all file events. */
  97.  
  98. /*
  99.  * There is one of the following structures for each of the
  100.  * handlers declared in a call to Tk_DoWhenIdle.  All of the
  101.  * currently-active handlers are linked together into a list.
  102.  */
  103.  
  104. typedef struct IdleHandler {
  105.     void (*proc)  _ANSI_ARGS_((ClientData clientData));
  106.                 /* Procedure to call. */
  107.     ClientData clientData;    /* Value to pass to proc. */
  108.     struct IdleHandler *nextPtr;/* Next in list of active handlers. */
  109. } IdleHandler;
  110.  
  111. static IdleHandler *idleList = NULL;
  112.                 /* First in list of all idle handlers. */
  113. static IdleHandler *lastIdlePtr = NULL;
  114.                 /* Last in list (or NULL for empty list). */
  115.  
  116. /*
  117.  * There's a potential problem if a handler is deleted while it's
  118.  * current (i.e. its procedure is executing), since Tk_HandleEvent
  119.  * will need to read the handler's "nextPtr" field when the procedure
  120.  * returns.  To handle this problem, structures of the type below
  121.  * indicate the next handler to be processed for any (recursively
  122.  * nested) dispatches in progress.  The nextHandler fields get
  123.  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
  124.  * also needs to know if the entire window gets deleted;  the winPtr
  125.  * field is set to zero if that particular window gets deleted.
  126.  */
  127.  
  128. typedef struct InProgress {
  129.     XEvent *eventPtr;         /* Event currently being handled. */
  130.     TkWindow *winPtr;         /* Window for event.  Gets set to None if
  131.                   * window is deleted while event is being
  132.                   * handled. */
  133.     TkEventHandler *nextHandler; /* Next handler in search. */
  134.     struct InProgress *nextPtr;     /* Next higher nested search. */
  135. } InProgress;
  136.  
  137. static InProgress *pendingPtr = NULL;
  138.                 /* Topmost search in progress, or
  139.                  * NULL if none. */
  140.  
  141. /*
  142.  * For each call to Tk_CreateGenericHandler, an instance of the following
  143.  * structure will be created.  All of the active handlers are linked into a
  144.  * list.
  145.  */
  146.  
  147. typedef struct GenericHandler {
  148.     Tk_GenericProc *proc;    /* Procedure to dispatch on all X events. */
  149.     ClientData clientData;    /* Client data to pass to procedure. */
  150.     int deleteFlag;        /* Flag to set when this handler is deleted. */
  151.     struct GenericHandler *nextPtr;
  152.                 /* Next handler in list of all generic
  153.                  * handlers, or NULL for end of list. */
  154. } GenericHandler;
  155.  
  156. static GenericHandler *genericList = NULL;
  157.                 /* First handler in the list, or NULL. */
  158. static GenericHandler *lastGenericPtr = NULL;
  159.                 /* Last handler in list. */
  160.  
  161. /*
  162.  * There's a potential problem if Tk_HandleEvent is entered recursively.
  163.  * A handler cannot be deleted physically until we have returned from
  164.  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
  165.  * its `next' entry.  We deal with the problem by using the `delete flag' and
  166.  * deleting handlers only when it's known that there's no handler active.
  167.  *
  168.  * The following variable has a non-zero value when a handler is active.
  169.  */
  170.  
  171. static int genericHandlersActive = 0;
  172.  
  173. /*
  174.  * Array of event masks corresponding to each X event:
  175.  */
  176.  
  177. static unsigned long eventMasks[] = {
  178.     0,
  179.     0,
  180.     KeyPressMask,            /* KeyPress */
  181.     KeyReleaseMask,            /* KeyRelease */
  182.     ButtonPressMask,            /* ButtonPress */
  183.     ButtonReleaseMask,            /* ButtonRelease */
  184.     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
  185.         |Button1MotionMask|Button2MotionMask|Button3MotionMask
  186.         |Button4MotionMask|Button5MotionMask,
  187.                     /* MotionNotify */
  188.     EnterWindowMask,            /* EnterNotify */
  189.     LeaveWindowMask,            /* LeaveNotify */
  190.     FocusChangeMask,            /* FocusIn */
  191.     FocusChangeMask,            /* FocusOut */
  192.     KeymapStateMask,            /* KeymapNotify */
  193.     ExposureMask,            /* Expose */
  194.     ExposureMask,            /* GraphicsExpose */
  195.     ExposureMask,            /* NoExpose */
  196.     VisibilityChangeMask,        /* VisibilityNotify */
  197.     SubstructureNotifyMask,        /* CreateNotify */
  198.     StructureNotifyMask,        /* DestroyNotify */
  199.     StructureNotifyMask,        /* UnmapNotify */
  200.     StructureNotifyMask,        /* MapNotify */
  201.     SubstructureRedirectMask,        /* MapRequest */
  202.     StructureNotifyMask,        /* ReparentNotify */
  203.     StructureNotifyMask,        /* ConfigureNotify */
  204.     SubstructureRedirectMask,        /* ConfigureRequest */
  205.     StructureNotifyMask,        /* GravityNotify */
  206.     ResizeRedirectMask,            /* ResizeRequest */
  207.     StructureNotifyMask,        /* CirculateNotify */
  208.     SubstructureRedirectMask,        /* CirculateRequest */
  209.     PropertyChangeMask,            /* PropertyNotify */
  210.     0,                    /* SelectionClear */
  211.     0,                    /* SelectionRequest */
  212.     0,                    /* SelectionNotify */
  213.     ColormapChangeMask,            /* ColormapNotify */
  214.     0,                    /* ClientMessage */
  215.     0,                    /* Mapping Notify */
  216. };
  217.  
  218. /*
  219.  * If someone has called Tk_RestrictEvents, the information below
  220.  * keeps track of it.
  221.  */
  222.  
  223. static Bool (*restrictProc)  _ANSI_ARGS_((Display *display, XEvent *eventPtr,
  224.     char *arg));        /* Procedure to call.  NULL means no
  225.                  * restrictProc is currently in effect. */
  226. static char *restrictArg;    /* Argument to pass to restrictProc. */
  227.  
  228. /*
  229.  * The following array keeps track of the last TK_NEVENTS X events, for
  230.  * memory dump analysis.  The tracing is only done if tkEventDebug is set
  231.  * to 1.
  232.  */
  233.  
  234. #define TK_NEVENTS 32
  235. static XEvent eventTrace[TK_NEVENTS];
  236. static int traceIndex = 0;
  237. int tkEventDebug = 0;
  238.  
  239. /*
  240.  *--------------------------------------------------------------
  241.  *
  242.  * Tk_CreateEventHandler --
  243.  *
  244.  *    Arrange for a given procedure to be invoked whenever
  245.  *    events from a given class occur in a given window.
  246.  *
  247.  * Results:
  248.  *    None.
  249.  *
  250.  * Side effects:
  251.  *    From now on, whenever an event of the type given by
  252.  *    mask occurs for token and is processed by Tk_HandleEvent,
  253.  *    proc will be called.  See the manual entry for details
  254.  *    of the calling sequence and return value for proc.
  255.  *
  256.  *--------------------------------------------------------------
  257.  */
  258.  
  259. void
  260. Tk_CreateEventHandler(token, mask, proc, clientData)
  261.     Tk_Window token;        /* Token for window in which to
  262.                  * create handler. */
  263.     unsigned long mask;        /* Events for which proc should
  264.                  * be called. */
  265.     Tk_EventProc *proc;        /* Procedure to call for each
  266.                  * selected event */
  267.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  268. {
  269.     register TkEventHandler *handlerPtr;
  270.     register TkWindow *winPtr = (TkWindow *) token;
  271.     int found;
  272.  
  273.     /*
  274.      * Skim through the list of existing handlers to (a) compute the
  275.      * overall event mask for the window (so we can pass this new
  276.      * value to the X system) and (b) see if there's already a handler
  277.      * declared with the same callback and clientData (if so, just
  278.      * change the mask).  If no existing handler matches, then create
  279.      * a new handler.
  280.      */
  281.  
  282.     found = 0;
  283.     if (winPtr->handlerList == NULL) {
  284.     handlerPtr = (TkEventHandler *) ckalloc(
  285.         (unsigned) sizeof(TkEventHandler));
  286.     winPtr->handlerList = handlerPtr;
  287.     goto initHandler;
  288.     } else {
  289.     for (handlerPtr = winPtr->handlerList; ;
  290.         handlerPtr = handlerPtr->nextPtr) {
  291.         if ((handlerPtr->proc == proc)
  292.             && (handlerPtr->clientData == clientData)) {
  293.         handlerPtr->mask = mask;
  294.         found = 1;
  295.         }
  296.         if (handlerPtr->nextPtr == NULL) {
  297.         break;
  298.         }
  299.     }
  300.     }
  301.  
  302.     /*
  303.      * Create a new handler if no matching old handler was found.
  304.      */
  305.  
  306.     if (!found) {
  307.     handlerPtr->nextPtr = (TkEventHandler *)
  308.         ckalloc(sizeof(TkEventHandler));
  309.     handlerPtr = handlerPtr->nextPtr;
  310.     initHandler:
  311.     handlerPtr->mask = mask;
  312.     handlerPtr->proc = proc;
  313.     handlerPtr->clientData = clientData;
  314.     handlerPtr->nextPtr = NULL;
  315.     }
  316.  
  317.     /*
  318.      * No need to call XSelectInput:  Tk always selects on all events
  319.      * for all windows (needed to support bindings on classes and "all").
  320.      */
  321. }
  322.  
  323. /*
  324.  *--------------------------------------------------------------
  325.  *
  326.  * Tk_DeleteEventHandler --
  327.  *
  328.  *    Delete a previously-created handler.
  329.  *
  330.  * Results:
  331.  *    None.
  332.  *
  333.  * Side effects:
  334.  *    If there existed a handler as described by the
  335.  *    parameters, the handler is deleted so that proc
  336.  *    will not be invoked again.
  337.  *
  338.  *--------------------------------------------------------------
  339.  */
  340.  
  341. void
  342. Tk_DeleteEventHandler(token, mask, proc, clientData)
  343.     Tk_Window token;        /* Same as corresponding arguments passed */
  344.     unsigned long mask;        /* previously to Tk_CreateEventHandler. */
  345.     Tk_EventProc *proc;
  346.     ClientData clientData;
  347. {
  348.     register TkEventHandler *handlerPtr;
  349.     register InProgress *ipPtr;
  350.     TkEventHandler *prevPtr;
  351.     register TkWindow *winPtr = (TkWindow *) token;
  352.  
  353.     /*
  354.      * Find the event handler to be deleted, or return
  355.      * immediately if it doesn't exist.
  356.      */
  357.  
  358.     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
  359.         prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
  360.     if (handlerPtr == NULL) {
  361.         return;
  362.     }
  363.     if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
  364.         && (handlerPtr->clientData == clientData)) {
  365.         break;
  366.     }
  367.     }
  368.  
  369.     /*
  370.      * If Tk_HandleEvent is about to process this handler, tell it to
  371.      * process the next one instead.
  372.      */
  373.  
  374.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  375.     if (ipPtr->nextHandler == handlerPtr) {
  376.         ipPtr->nextHandler = handlerPtr->nextPtr;
  377.     }
  378.     }
  379.  
  380.     /*
  381.      * Free resources associated with the handler.
  382.      */
  383.  
  384.     if (prevPtr == NULL) {
  385.     winPtr->handlerList = handlerPtr->nextPtr;
  386.     } else {
  387.     prevPtr->nextPtr = handlerPtr->nextPtr;
  388.     }
  389.     ckfree((char *) handlerPtr);
  390.  
  391.  
  392.     /*
  393.      * No need to call XSelectInput:  Tk always selects on all events
  394.      * for all windows (needed to support bindings on classes and "all").
  395.      */
  396. }
  397.  
  398. /*--------------------------------------------------------------
  399.  *
  400.  * Tk_CreateGenericHandler --
  401.  *
  402.  *    Register a procedure to be called on each X event, regardless
  403.  *    of display or window.  Generic handlers are useful for capturing
  404.  *    events that aren't associated with windows, or events for windows
  405.  *    not managed by Tk.
  406.  *
  407.  * Results:
  408.  *    None.
  409.  *
  410.  * Side Effects:
  411.  *    From now on, whenever an X event is given to Tk_HandleEvent,
  412.  *    invoke proc, giving it clientData and the event as arguments.
  413.  *
  414.  *--------------------------------------------------------------
  415.  */
  416.  
  417. void
  418. Tk_CreateGenericHandler(proc, clientData)
  419.      Tk_GenericProc *proc;    /* Procedure to call on every event. */
  420.      ClientData clientData;    /* One-word value to pass to proc. */
  421. {
  422.     GenericHandler *handlerPtr;
  423.     
  424.     handlerPtr = (GenericHandler *) ckalloc (sizeof (GenericHandler));
  425.     
  426.     handlerPtr->proc = proc;
  427.     handlerPtr->clientData = clientData;
  428.     handlerPtr->deleteFlag = 0;
  429.     handlerPtr->nextPtr = NULL;
  430.     if (genericList == NULL) {
  431.     genericList = handlerPtr;
  432.     } else {
  433.     lastGenericPtr->nextPtr = handlerPtr;
  434.     }
  435.     lastGenericPtr = handlerPtr;
  436. }
  437.  
  438. /*
  439.  *--------------------------------------------------------------
  440.  *
  441.  * Tk_DeleteGenericHandler --
  442.  *
  443.  *    Delete a previously-created generic handler.
  444.  *
  445.  * Results:
  446.  *    None.
  447.  *
  448.  * Side Effects:
  449.  *    If there existed a handler as described by the parameters,
  450.  *    that handler is logically deleted so that proc will not be
  451.  *    invoked again.  The physical deletion happens in the event
  452.  *    loop in Tk_HandleEvent.
  453.  *
  454.  *--------------------------------------------------------------
  455.  */
  456.  
  457. void
  458. Tk_DeleteGenericHandler(proc, clientData)
  459.      Tk_GenericProc *proc;
  460.      ClientData clientData;
  461. {
  462.     GenericHandler * handler;
  463.     
  464.     for (handler = genericList; handler; handler = handler->nextPtr) {
  465.     if ((handler->proc == proc) && (handler->clientData == clientData)) {
  466.         handler->deleteFlag = 1;
  467.     }
  468.     }
  469. }
  470.  
  471. /*
  472.  *--------------------------------------------------------------
  473.  *
  474.  * Tk_HandleEvent --
  475.  *
  476.  *    Given an event, invoke all the handlers that have
  477.  *    been registered for the event.
  478.  *
  479.  * Results:
  480.  *    None.
  481.  *
  482.  * Side effects:
  483.  *    Depends on the handlers.
  484.  *
  485.  *--------------------------------------------------------------
  486.  */
  487.  
  488. void
  489. Tk_HandleEvent(eventPtr)
  490.     XEvent *eventPtr;        /* Event to dispatch. */
  491. {
  492.     register TkEventHandler *handlerPtr;
  493.     register GenericHandler *genericPtr;
  494.     register GenericHandler *genPrevPtr;
  495.     TkWindow *winPtr;
  496.     register unsigned long mask;
  497.     InProgress ip;
  498.     Window handlerWindow;
  499.  
  500.     /* 
  501.      * First off, invoke all the generic event handlers (those that are
  502.      * invoked for all events).  If a generic event handler reports that
  503.      * an event is fully processed, go no further.
  504.      */
  505.  
  506.     for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
  507.     if (genericPtr->deleteFlag) {
  508.         if (!genericHandlersActive) {
  509.         GenericHandler *tmpPtr;
  510.  
  511.         /*
  512.          * This handler needs to be deleted and there are no
  513.          * calls pending through the handler, so now is a safe
  514.          * time to delete it.
  515.          */
  516.  
  517.         tmpPtr = genericPtr->nextPtr;
  518.         if (genPrevPtr == NULL) {
  519.             genericList = tmpPtr;
  520.         } else {
  521.             genPrevPtr->nextPtr = tmpPtr;
  522.         }
  523.         (void) ckfree((char *) genericPtr);
  524.         genericPtr = tmpPtr;
  525.         continue;
  526.         }
  527.     } else {
  528.         int done;
  529.  
  530.         genericHandlersActive++;
  531.         done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
  532.         genericHandlersActive--;
  533.         if (done) {
  534.         return;
  535.         }
  536.     }
  537.     genPrevPtr = genericPtr;
  538.     genericPtr = genPrevPtr->nextPtr;
  539.     }
  540.  
  541.     /*
  542.      * Events selected by StructureNotify look the same as those
  543.      * selected by SubstructureNotify;  the only difference is
  544.      * whether the "event" and "window" fields are the same.
  545.      * Check it out and convert StructureNotify to
  546.      * SubstructureNotify if necessary.
  547.      */
  548.  
  549.     handlerWindow = eventPtr->xany.window;
  550.     mask = eventMasks[eventPtr->xany.type];
  551.     if (mask == StructureNotifyMask) {
  552.     if (eventPtr->xmap.event != eventPtr->xmap.window) {
  553.         mask = SubstructureNotifyMask;
  554.         handlerWindow = eventPtr->xmap.event;
  555.     }
  556.     }
  557.     if (XFindContext(eventPtr->xany.display, handlerWindow,
  558.         tkWindowContext, (caddr_t *) &winPtr) != 0) {
  559.  
  560.     /*
  561.      * There isn't a TkWindow structure for this window.
  562.      * However, if the event is a PropertyNotify event then call
  563.      * the selection manager (it deals beneath-the-table with
  564.      * certain properties).
  565.      */
  566.  
  567.     if (eventPtr->type == PropertyNotify) {
  568.         TkSelPropProc(eventPtr);
  569.     }
  570.     return;
  571.     }
  572.  
  573.     /*
  574.      * Redirect KeyPress and KeyRelease events if input focussing
  575.      * is happening.  Map the x and y coordinates between the two
  576.      * windows, if possible (make both -1 if the map-from and map-to
  577.      * windows don't share the same top-level window).
  578.      */
  579.  
  580.     if (mask & (KeyPressMask|KeyReleaseMask)) {
  581.     winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
  582.         if (winPtr->mainPtr->focusPtr != NULL) {
  583.         TkWindow *focusPtr;
  584.         int winX, winY, focusX, focusY;
  585.     
  586.         focusPtr = winPtr->mainPtr->focusPtr;
  587.         if ((focusPtr->display != winPtr->display)
  588.             || (focusPtr->screenNum != winPtr->screenNum)) {
  589.         eventPtr->xkey.x = -1;
  590.         eventPtr->xkey.y = -1;
  591.         } else {
  592.         Tk_GetRootCoords((Tk_Window) winPtr, &winX, &winY);
  593.         Tk_GetRootCoords((Tk_Window) focusPtr, &focusX, &focusY);
  594.         eventPtr->xkey.x -= focusX - winX;
  595.         eventPtr->xkey.y -= focusY - winY;
  596.         }
  597.         eventPtr->xkey.window = focusPtr->window;
  598.         winPtr = focusPtr;
  599.     }
  600.     }
  601.  
  602.     /*
  603.      * Call a grab-related procedure to do special processing on
  604.      * pointer events.
  605.      */
  606.  
  607.     if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
  608.         |EnterWindowMask|LeaveWindowMask)) {
  609.     if (mask & (ButtonPressMask|ButtonReleaseMask)) {
  610.         winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
  611.     } else if (mask & PointerMotionMask) {
  612.         winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
  613.     } else {
  614.         winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
  615.     }
  616.     if (TkPointerEvent(eventPtr, winPtr) == 0) {
  617.         return;
  618.     }
  619.     }
  620.  
  621.     /*
  622.      * For events where it hasn't already been done, update the current
  623.      * time in the display.
  624.      */
  625.  
  626.     if (eventPtr->type == PropertyNotify) {
  627.     winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
  628.     }
  629.  
  630.     /*
  631.      * There's a potential interaction here with Tk_DeleteEventHandler.
  632.      * Read the documentation for pendingPtr.
  633.      */
  634.  
  635.     ip.eventPtr = eventPtr;
  636.     ip.winPtr = winPtr;
  637.     ip.nextHandler = NULL;
  638.     ip.nextPtr = pendingPtr;
  639.     pendingPtr = &ip;
  640.     if (mask == 0) {
  641.     if ((eventPtr->type == SelectionClear)
  642.         || (eventPtr->type == SelectionRequest)
  643.         || (eventPtr->type == SelectionNotify)) {
  644.         TkSelEventProc((Tk_Window) winPtr, eventPtr);
  645.     }
  646.     } else {
  647.     for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
  648.         if ((handlerPtr->mask & mask) != 0) {
  649.         ip.nextHandler = handlerPtr->nextPtr;
  650.         (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
  651.         handlerPtr = ip.nextHandler;
  652.         } else {
  653.         handlerPtr = handlerPtr->nextPtr;
  654.         }
  655.     }
  656.  
  657.     /*
  658.      * Pass the event to the "bind" command mechanism.  But, don't
  659.      * do this for SubstructureNotify events.  The "bind" command
  660.      * doesn't support them anyway, and it's easier to filter out
  661.      * these events here than in the lower-level procedures.
  662.      */
  663.  
  664.     if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
  665.         TkBindEventProc(winPtr, eventPtr);
  666.     }
  667.     }
  668.     pendingPtr = ip.nextPtr;
  669. }
  670.  
  671. /*
  672.  *--------------------------------------------------------------
  673.  *
  674.  * Tk_CreateFileHandler --
  675.  *
  676.  *    Arrange for a given procedure to be invoked whenever
  677.  *    a given file becomes readable or writable.
  678.  *
  679.  * Results:
  680.  *    None.
  681.  *
  682.  * Side effects:
  683.  *    From now on, whenever the I/O channel given by fd becomes
  684.  *    ready in the way indicated by mask, proc will be invoked.
  685.  *    See the manual entry for details on the calling sequence
  686.  *    to proc.  If fd is already registered then the old mask
  687.  *    and proc and clientData values will be replaced with
  688.  *    new ones.
  689.  *
  690.  *--------------------------------------------------------------
  691.  */
  692.  
  693. void
  694. Tk_CreateFileHandler(fd, mask, proc, clientData)
  695.     int fd;            /* Integer identifier for stream. */
  696.     int mask;            /* OR'ed combination of TK_READABLE,
  697.                  * TK_WRITABLE, and TK_EXCEPTION:
  698.                  * indicates conditions under which
  699.                  * proc should be called. */
  700.     Tk_FileProc *proc;        /* Procedure to call for each
  701.                  * selected event.  NULL means that
  702.                  * this is a display, and that
  703.                  * clientData is the (Display *)
  704.                  * for it, and that events should
  705.                  * be handled automatically. */
  706.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  707. {
  708.     register FileEvent *filePtr;
  709.     int index;
  710.  
  711.     if (fd >= OPEN_MAX) {
  712.     panic("Tk_CreatefileHandler can't handle file id %d", fd);
  713.     }
  714.  
  715.     /*
  716.      * Make sure the file isn't already registered.  Create a
  717.      * new record in the normal case where there's no existing
  718.      * record.
  719.      */
  720.  
  721.     for (filePtr = fileList; filePtr != NULL;
  722.         filePtr = filePtr->nextPtr) {
  723.     if (filePtr->fd == fd) {
  724.         break;
  725.     }
  726.     }
  727.     index = fd/(8*sizeof(int));
  728.     if (filePtr == NULL) {
  729.     filePtr = (FileEvent *) ckalloc(sizeof(FileEvent));
  730.     filePtr->fd = fd;
  731.     filePtr->readPtr = &ready[index];
  732.     filePtr->writePtr = &ready[index+MASK_SIZE];
  733.     filePtr->exceptPtr = &ready[index+2*MASK_SIZE];
  734.     filePtr->mask = 1 << (fd%(8*sizeof(int)));
  735.     filePtr->nextPtr = fileList;
  736.     fileList = filePtr;
  737.     } else {
  738.     if (masks[index] & filePtr->mask) {
  739.         readCount--;
  740.         *filePtr->readPtr &= ~filePtr->mask;
  741.         masks[index] &= ~filePtr->mask;
  742.     }
  743.     if (masks[index+MASK_SIZE] & filePtr->mask) {
  744.         writeCount--;
  745.         *filePtr->writePtr &= ~filePtr->mask;
  746.         masks[index+MASK_SIZE] &= ~filePtr->mask;
  747.     }
  748.     if (masks[index+2*MASK_SIZE] & filePtr->mask) {
  749.         exceptCount--;
  750.         *filePtr->exceptPtr &= ~filePtr->mask;
  751.         masks[index+2*MASK_SIZE] &= ~filePtr->mask;
  752.     }
  753.     }
  754.  
  755.     /*
  756.      * The remainder of the initialization below is done
  757.      * regardless of whether or not this is a new record
  758.      * or a modification of an old one.
  759.      */
  760.  
  761.     if (mask & TK_READABLE) {
  762.     masks[index] |= filePtr->mask;
  763.     readCount++;
  764.     }
  765.     readPtr = (readCount == 0 ? NULL : &ready[0]);
  766.  
  767.     if (mask & TK_WRITABLE) {
  768.     masks[index+MASK_SIZE] |= filePtr->mask;
  769.     writeCount++;
  770.     }
  771.     writePtr = (writeCount == 0 ? NULL : &ready[MASK_SIZE]);
  772.  
  773.     if (mask & TK_EXCEPTION) {
  774.     masks[index+2*MASK_SIZE] |= filePtr->mask;
  775.     exceptCount++;
  776.     }
  777.     exceptPtr = (exceptCount == 0 ? NULL : &ready[2*MASK_SIZE]);
  778.  
  779.     filePtr->proc = proc;
  780.     filePtr->clientData = clientData;
  781.  
  782.     if (numFds <= fd) {
  783.     numFds = fd+1;
  784.     }
  785. }
  786.  
  787. /*
  788.  *--------------------------------------------------------------
  789.  *
  790.  * Tk_DeleteFileHandler --
  791.  *
  792.  *    Cancel a previously-arranged callback arrangement for
  793.  *    a file.
  794.  *
  795.  * Results:
  796.  *    None.
  797.  *
  798.  * Side effects:
  799.  *    If a callback was previously registered on fd, remove it.
  800.  *
  801.  *--------------------------------------------------------------
  802.  */
  803.  
  804. void
  805. Tk_DeleteFileHandler(fd)
  806.     int fd;            /* Stream id for which to remove
  807.                  * callback procedure. */
  808. {
  809.     register FileEvent *filePtr;
  810.     FileEvent *prevPtr;
  811.     int index;
  812.  
  813.     /*
  814.      * Find the entry for the given file (and return if there
  815.      * isn't one).
  816.      */
  817.  
  818.     for (prevPtr = NULL, filePtr = fileList; ;
  819.         prevPtr = filePtr, filePtr = filePtr->nextPtr) {
  820.     if (filePtr == NULL) {
  821.         return;
  822.     }
  823.     if (filePtr->fd == fd) {
  824.         break;
  825.     }
  826.     }
  827.  
  828.     /*
  829.      * Clean up information in the callback record.
  830.      */
  831.  
  832.     index = filePtr->fd/(8*sizeof(int));
  833.     if (masks[index] & filePtr->mask) {
  834.     readCount--;
  835.     *filePtr->readPtr &= ~filePtr->mask;
  836.     masks[index] &= ~filePtr->mask;
  837.     }
  838.     if (masks[index+MASK_SIZE] & filePtr->mask) {
  839.     writeCount--;
  840.     *filePtr->writePtr &= ~filePtr->mask;
  841.     masks[index+MASK_SIZE] &= ~filePtr->mask;
  842.     }
  843.     if (masks[index+2*MASK_SIZE] & filePtr->mask) {
  844.     exceptCount--;
  845.     *filePtr->exceptPtr &= ~filePtr->mask;
  846.     masks[index+2*MASK_SIZE] &= ~filePtr->mask;
  847.     }
  848.     if (prevPtr == NULL) {
  849.     fileList = filePtr->nextPtr;
  850.     } else {
  851.     prevPtr->nextPtr = filePtr->nextPtr;
  852.     }
  853.     ckfree((char *) filePtr);
  854.  
  855.     /*
  856.      * Recompute numFds.
  857.      */
  858.  
  859.     numFds = 0;
  860.     for (filePtr = fileList; filePtr != NULL;
  861.         filePtr = filePtr->nextPtr) {
  862.     if (numFds <= filePtr->fd) {
  863.         numFds = filePtr->fd+1;
  864.     }
  865.     }
  866. }
  867.  
  868. /*
  869.  *--------------------------------------------------------------
  870.  *
  871.  * Tk_CreateTimerHandler --
  872.  *
  873.  *    Arrange for a given procedure to be invoked at a particular
  874.  *    time in the future.
  875.  *
  876.  * Results:
  877.  *    The return value is a token for the timer event, which
  878.  *    may be used to delete the event before it fires.
  879.  *
  880.  * Side effects:
  881.  *    When milliseconds have elapsed, proc will be invoked
  882.  *    exactly once.
  883.  *
  884.  *--------------------------------------------------------------
  885.  */
  886.  
  887. Tk_TimerToken
  888. Tk_CreateTimerHandler(milliseconds, proc, clientData)
  889.     int milliseconds;        /* How many milliseconds to wait
  890.                  * before invoking proc. */
  891.     Tk_TimerProc *proc;        /* Procedure to invoke. */
  892.     ClientData clientData;    /* Arbitrary data to pass to proc. */
  893. {
  894.     register TimerEvent *timerPtr, *tPtr2, *prevPtr;
  895.     static int id = 0;
  896.  
  897.     timerPtr = (TimerEvent *) ckalloc(sizeof(TimerEvent));
  898.  
  899.     /*
  900.      * Compute when the event should fire.
  901.      */
  902.  
  903.     (void) gettimeofday(&timerPtr->time, (struct timezone *) NULL);
  904.     timerPtr->time.tv_sec += milliseconds/1000;
  905.     timerPtr->time.tv_usec += (milliseconds%1000)*1000;
  906.     if (timerPtr->time.tv_usec > 1000000) {
  907.     timerPtr->time.tv_usec -= 1000000;
  908.     timerPtr->time.tv_sec += 1;
  909.     }
  910.  
  911.     /*
  912.      * Fill in other fields for the event.
  913.      */
  914.  
  915.     timerPtr->proc = proc;
  916.     timerPtr->clientData = clientData;
  917.     id++;
  918.     timerPtr->token = (Tk_TimerToken) id;
  919.  
  920.     /*
  921.      * Add the event to the queue in the correct position
  922.      * (ordered by event firing time).
  923.      */
  924.  
  925.     for (tPtr2 = timerQueue, prevPtr = NULL; tPtr2 != NULL;
  926.         prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
  927.     if ((tPtr2->time.tv_sec > timerPtr->time.tv_sec)
  928.         || ((tPtr2->time.tv_sec == timerPtr->time.tv_sec)
  929.         && (tPtr2->time.tv_usec > timerPtr->time.tv_usec))) {
  930.         break;
  931.     }
  932.     }
  933.     if (prevPtr == NULL) {
  934.     timerPtr->nextPtr = timerQueue;
  935.     timerQueue = timerPtr;
  936.     } else {
  937.     timerPtr->nextPtr = prevPtr->nextPtr;
  938.     prevPtr->nextPtr = timerPtr;
  939.     }
  940.     return timerPtr->token;
  941. }
  942.  
  943. /*
  944.  *--------------------------------------------------------------
  945.  *
  946.  * Tk_DeleteTimerHandler --
  947.  *
  948.  *    Delete a previously-registered timer handler.
  949.  *
  950.  * Results:
  951.  *    None.
  952.  *
  953.  * Side effects:
  954.  *    Destroy the timer callback identified by TimerToken,
  955.  *    so that its associated procedure will not be called.
  956.  *    If the callback has already fired, or if the given
  957.  *    token doesn't exist, then nothing happens.
  958.  *
  959.  *--------------------------------------------------------------
  960.  */
  961.  
  962. void
  963. Tk_DeleteTimerHandler(token)
  964.     Tk_TimerToken token;    /* Result previously returned by
  965.                  * Tk_DeleteTimerHandler. */
  966. {
  967.     register TimerEvent *timerPtr, *prevPtr;
  968.  
  969.     for (timerPtr = timerQueue, prevPtr = NULL; timerPtr != NULL;
  970.         prevPtr = timerPtr, timerPtr = timerPtr->nextPtr) {
  971.     if (timerPtr->token != token) {
  972.         continue;
  973.     }
  974.     if (prevPtr == NULL) {
  975.         timerQueue = timerPtr->nextPtr;
  976.     } else {
  977.         prevPtr->nextPtr = timerPtr->nextPtr;
  978.     }
  979.     ckfree((char *) timerPtr);
  980.     return;
  981.     }
  982. }
  983.  
  984. /*
  985.  *--------------------------------------------------------------
  986.  *
  987.  * Tk_DoWhenIdle --
  988.  *
  989.  *    Arrange for proc to be invoked the next time the
  990.  *    system is idle (i.e., just before the next time
  991.  *    that Tk_DoOneEvent would have to wait for something
  992.  *    to happen).
  993.  *
  994.  * Results:
  995.  *    None.
  996.  *
  997.  * Side effects:
  998.  *    Proc will eventually be called, with clientData
  999.  *    as argument.  See the manual entry for details.
  1000.  *
  1001.  *--------------------------------------------------------------
  1002.  */
  1003.  
  1004. void
  1005. Tk_DoWhenIdle(proc, clientData)
  1006.     Tk_IdleProc *proc;        /* Procedure to invoke. */
  1007.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  1008. {
  1009.     register IdleHandler *idlePtr;
  1010.  
  1011.     idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler));
  1012.     idlePtr->proc = proc;
  1013.     idlePtr->clientData = clientData;
  1014.     idlePtr->nextPtr = NULL;
  1015.     if (lastIdlePtr == NULL) {
  1016.     idleList = idlePtr;
  1017.     } else {
  1018.     lastIdlePtr->nextPtr = idlePtr;
  1019.     }
  1020.     lastIdlePtr = idlePtr;
  1021. }
  1022.  
  1023. /*
  1024.  *----------------------------------------------------------------------
  1025.  *
  1026.  * Tk_CancelIdleCall --
  1027.  *
  1028.  *    If there are any when-idle calls requested to a given procedure
  1029.  *    with given clientData, cancel all of them.
  1030.  *
  1031.  * Results:
  1032.  *    None.
  1033.  *
  1034.  * Side effects:
  1035.  *    If the proc/clientData combination were on the when-idle list,
  1036.  *    they are removed so that they will never be called.
  1037.  *
  1038.  *----------------------------------------------------------------------
  1039.  */
  1040.  
  1041. void
  1042. Tk_CancelIdleCall(proc, clientData)
  1043.     Tk_IdleProc *proc;        /* Procedure that was previously registered. */
  1044.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  1045. {
  1046.     register IdleHandler *idlePtr, *prevPtr;
  1047.     IdleHandler *nextPtr;
  1048.  
  1049.     for (prevPtr = NULL, idlePtr = idleList; idlePtr != NULL;
  1050.         prevPtr = idlePtr, idlePtr = idlePtr->nextPtr) {
  1051.     while ((idlePtr->proc == proc)
  1052.         && (idlePtr->clientData == clientData)) {
  1053.         nextPtr = idlePtr->nextPtr;
  1054.         ckfree((char *) idlePtr);
  1055.         idlePtr = nextPtr;
  1056.         if (prevPtr == NULL) {
  1057.         idleList = idlePtr;
  1058.         } else {
  1059.         prevPtr->nextPtr = idlePtr;
  1060.         }
  1061.         if (idlePtr == NULL) {
  1062.         lastIdlePtr = prevPtr;
  1063.         return;
  1064.         }
  1065.     }
  1066.     }
  1067. }
  1068.  
  1069. /*
  1070.  *--------------------------------------------------------------
  1071.  *
  1072.  * Tk_DoOneEvent --
  1073.  *
  1074.  *    Process a single event of some sort.  If there's no
  1075.  *    work to do, wait for an event to occur, then process
  1076.  *    it.
  1077.  *
  1078.  * Results:
  1079.  *    The return value is 1 if the procedure actually found
  1080.  *    an event to process.  If no event was found then 0 is
  1081.  *    returned.
  1082.  *
  1083.  * Side effects:
  1084.  *    May delay execution of process while waiting for an
  1085.  *    X event, X error, file-ready event, or timer event.
  1086.  *    The handling of the event could cause additional
  1087.  *    side effects.  Collapses sequences of mouse-motion
  1088.  *    events for the same window into a single event by
  1089.  *    delaying motion event processing.
  1090.  *
  1091.  *--------------------------------------------------------------
  1092.  */
  1093.  
  1094. int
  1095. Tk_DoOneEvent(flags)
  1096.     int flags;            /* Miscellaneous flag values:  may be any
  1097.                  * combination of TK_DONT_WAIT, TK_X_EVENTS,
  1098.                  * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
  1099.                  * TK_IDLE_EVENTS. */
  1100. {
  1101.     register FileEvent *filePtr;
  1102.     struct timeval curTime, timeout, *timeoutPtr;
  1103.     int numFound;
  1104.     static XEvent delayedMotionEvent;    /* Used to hold motion events that
  1105.                      * are being saved until later. */
  1106.     static int eventDelayed = 0;    /* Non-zero means there is an event
  1107.                      * in delayedMotionEvent. */
  1108.  
  1109.     if ((flags & TK_ALL_EVENTS) == 0) {
  1110.     flags |= TK_ALL_EVENTS;
  1111.     }
  1112.  
  1113.     /*
  1114.      * Phase One: see if there's already something ready
  1115.      * (either a file or a display) that was left over
  1116.      * from before (i.e don't do a select, just check the
  1117.      * bits from the last select).
  1118.      */
  1119.  
  1120.     checkFiles:
  1121.     for (filePtr = fileList; filePtr != NULL;
  1122.         filePtr = filePtr->nextPtr) {
  1123.     int mask;
  1124.  
  1125.     /*
  1126.      * Displays:  flush output, check for queued events,
  1127.      * and read events from the server if display is ready.
  1128.      * If there are any events, process one and then
  1129.      * return.
  1130.      */
  1131.  
  1132.     if ((filePtr->proc == NULL) && (flags & TK_X_EVENTS)) {
  1133.         Display *display = (Display *) filePtr->clientData;
  1134.         XEvent event;
  1135.  
  1136.         XFlush(display);
  1137.         if ((*filePtr->readPtr) & filePtr->mask) {
  1138.         *filePtr->readPtr &= ~filePtr->mask;
  1139.         if (XEventsQueued(display, QueuedAfterReading) == 0) {
  1140.  
  1141.             /*
  1142.              * Things are very tricky if there aren't any events
  1143.              * readable at this point (after all, there was
  1144.              * supposedly data available on the connection).
  1145.              * A couple of things could have occurred:
  1146.              * 
  1147.              * One possibility is that there were only error events
  1148.              * in the input from the server.  If this happens,
  1149.              * we should return (we don't want to go to sleep
  1150.              * in XNextEvent below, since this would block out
  1151.              * other sources of input to the process).
  1152.              *
  1153.              * Another possibility is that our connection to the
  1154.              * server has been closed.  This will not necessarily
  1155.              * be detected in XEventsQueued (!!), so if we just
  1156.              * return then there will be an infinite loop.  To
  1157.              * detect such an error, generate a NoOp protocol
  1158.              * request to exercise the connection to the server,
  1159.              * then return.  However, must disable SIGPIPE while
  1160.              * sending the event, or else the process will die
  1161.              * from the signal and won't invoke the X error
  1162.              * function to print a nice message.
  1163.              */
  1164.  
  1165.             void (*oldHandler)();
  1166.  
  1167.             oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
  1168.             XNoOp(display);
  1169.             XFlush(display);
  1170.             (void) signal(SIGPIPE, oldHandler);
  1171.             return 1;
  1172.         }
  1173.         if (restrictProc != NULL) {
  1174.             if (!XCheckIfEvent(display, &event, restrictProc,
  1175.                 restrictArg)) {
  1176.             return 1;
  1177.             }
  1178.         } else {
  1179.             XNextEvent(display, &event);
  1180.         }
  1181.         } else {
  1182.         if (QLength(display) == 0) {
  1183.             continue;
  1184.         }
  1185.         if (restrictProc != NULL) {
  1186.             if (!XCheckIfEvent(display, &event, restrictProc,
  1187.                 restrictArg)) {
  1188.             continue;
  1189.             }
  1190.         } else {
  1191.             XNextEvent(display, &event);
  1192.         }
  1193.         }
  1194.  
  1195.         /*
  1196.          * Got an event.  Deal with mouse-motion-collapsing and
  1197.          * event-delaying here.  If there's already an event delayed,
  1198.          * then process that event if it's incompatible with the new
  1199.          * event (new event not mouse motion, or window changed, or
  1200.          * state changed).  If the new event is mouse motion, then
  1201.          * don't process it now;  delay it until later in the hopes
  1202.          * that it can be merged with other mouse motion events
  1203.          * immediately following.
  1204.          */
  1205.  
  1206.         if (tkEventDebug) {
  1207.         eventTrace[traceIndex] = event;
  1208.         traceIndex = (traceIndex+1) % TK_NEVENTS;
  1209.         }
  1210.  
  1211.         if (eventDelayed) {
  1212.         if (((event.type != MotionNotify)
  1213.                 && (event.type != GraphicsExpose)
  1214.                 && (event.type != NoExpose)
  1215.                 && (event.type != Expose))
  1216.             || (event.xmotion.display
  1217.                 != delayedMotionEvent.xmotion.display)
  1218.             || (event.xmotion.window
  1219.                 != delayedMotionEvent.xmotion.window)) {
  1220.             XEvent copy;
  1221.  
  1222.             /*
  1223.              * Must copy the event out of delayedMotionEvent before
  1224.              * processing it, in order to allow recursive calls to
  1225.              * Tk_DoOneEvent as part of the handler.
  1226.              */
  1227.  
  1228.             copy = delayedMotionEvent;
  1229.             eventDelayed = 0;
  1230.             Tk_HandleEvent(©);
  1231.         }
  1232.         }
  1233.         if (event.type == MotionNotify) {
  1234.         delayedMotionEvent = event;
  1235.         eventDelayed = 1;
  1236.         } else {
  1237.         Tk_HandleEvent(&event);
  1238.         }
  1239.         return 1;
  1240.     }
  1241.  
  1242.     /*
  1243.      * Not a display:  if the file is ready, call the
  1244.      * appropriate handler.
  1245.      */
  1246.  
  1247.     if (((*filePtr->readPtr | *filePtr->writePtr
  1248.         | *filePtr->exceptPtr) & filePtr->mask) == 0) {
  1249.         continue;
  1250.     }
  1251.     if (!(flags & TK_FILE_EVENTS)) {
  1252.         continue;
  1253.     }
  1254.     mask = 0;
  1255.     if (*filePtr->readPtr & filePtr->mask) {
  1256.         mask |= TK_READABLE;
  1257.         *filePtr->readPtr &= ~filePtr->mask;
  1258.     }
  1259.     if (*filePtr->writePtr & filePtr->mask) {
  1260.         mask |= TK_WRITABLE;
  1261.         *filePtr->writePtr &= ~filePtr->mask;
  1262.     }
  1263.     if (*filePtr->exceptPtr & filePtr->mask) {
  1264.         mask |= TK_EXCEPTION;
  1265.         *filePtr->exceptPtr &= ~filePtr->mask;
  1266.     }
  1267.     (*filePtr->proc)(filePtr->clientData, mask);
  1268.     return 1;
  1269.     }
  1270.  
  1271.     /*
  1272.      * Phase Two: get the current time and see if any timer
  1273.      * events are ready to fire.  If so, fire one and return.
  1274.      */
  1275.  
  1276.     checkTime:
  1277.     if ((timerQueue != NULL) && (flags & TK_TIMER_EVENTS)) {
  1278.     register TimerEvent *timerPtr = timerQueue;
  1279.  
  1280.     (void) gettimeofday(&curTime, (struct timezone *) NULL);
  1281.     if ((timerPtr->time.tv_sec < curTime.tv_sec)
  1282.         || ((timerPtr->time.tv_sec == curTime.tv_sec)
  1283.         &&  (timerPtr->time.tv_usec < curTime.tv_usec))) {
  1284.         timerQueue = timerPtr->nextPtr;
  1285.         (*timerPtr->proc)(timerPtr->clientData);
  1286.         ckfree((char *) timerPtr);
  1287.         return 1;
  1288.     }
  1289.     }
  1290.  
  1291.  
  1292.     /*
  1293.      * Phase Three: if there is a delayed motion event, process it
  1294.      * now, before any DoWhenIdle handlers.  Better to process before
  1295.      * idle handlers than after, because the goal of idle handlers is
  1296.      * to delay until after all pending events have been processed.
  1297.      * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
  1298.      * so that the event handler can call Tk_DoOneEvent recursively
  1299.      * without infinite looping.
  1300.      */
  1301.  
  1302.     if ((eventDelayed) && (flags & TK_X_EVENTS)) {
  1303.     XEvent copy;
  1304.  
  1305.     copy = delayedMotionEvent;
  1306.     eventDelayed = 0;
  1307.     Tk_HandleEvent(©);
  1308.     return 1;
  1309.     }
  1310.  
  1311.     /*
  1312.      * Phase Four: if there are DoWhenIdle requests pending (or
  1313.      * if we're not allowed to block), then do a select with an
  1314.      * instantaneous timeout.  If a ready file is found, then go
  1315.      * back to process it.
  1316.      */
  1317.  
  1318.     if (((idleList != NULL) && (flags & TK_IDLE_EVENTS))
  1319.         || (flags & TK_DONT_WAIT)) {
  1320.     if (flags & (TK_X_EVENTS|TK_FILE_EVENTS)) {
  1321.         memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
  1322.         timeout.tv_sec = timeout.tv_usec = 0;
  1323.         do {
  1324.         numFound = select(numFds, (SELECT_MASK *) readPtr,
  1325.             (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
  1326.             &timeout);
  1327.         } while ((numFound == -1) && (errno == EINTR));
  1328.         if (numFound > 0) {
  1329.         goto checkFiles;
  1330.         }
  1331.     }
  1332.     }
  1333.  
  1334.     /*
  1335.      * Phase Five:  process all pending DoWhenIdle requests.
  1336.      */
  1337.  
  1338.     if ((idleList != NULL) && (flags & TK_IDLE_EVENTS)) {
  1339.     register IdleHandler *idlePtr;
  1340.  
  1341.     /*
  1342.      * If you change the code below, be aware that new handlers
  1343.      * can get added to the list while the current one is being
  1344.      * processed.
  1345.      *
  1346.      * NOTE!  Must remove the entry from the list before calling
  1347.      * it, in case the idle handler calls Tk_DoOneEvent:  don't
  1348.      * want to loop infinitely.  Must also be careful because
  1349.      * Tk_CancelIdleCall could change the list during the call.
  1350.      */
  1351.  
  1352.     while (idleList != NULL) {
  1353.         idlePtr = idleList;
  1354.         idleList = idlePtr->nextPtr;
  1355.         if (idleList == NULL) {
  1356.         lastIdlePtr = NULL;
  1357.         }
  1358.         (*idlePtr->proc)(idlePtr->clientData);
  1359.         ckfree((char *) idlePtr);
  1360.     }
  1361.     return 1;
  1362.     }
  1363.  
  1364.     /*
  1365.      * Phase Six: do a select to wait for either one of the
  1366.      * files to become ready or for the first timer event to
  1367.      * fire.  Then go back to process the event.
  1368.      */
  1369.  
  1370.     if ((flags & TK_DONT_WAIT)
  1371.         || !(flags & (TK_TIMER_EVENTS|TK_FILE_EVENTS|TK_X_EVENTS))) {
  1372.     return 0;
  1373.     }
  1374.     if ((timerQueue == NULL) || !(flags & TK_TIMER_EVENTS)) {
  1375.     timeoutPtr = NULL;
  1376.     } else {
  1377.     timeoutPtr = &timeout;
  1378.     timeout.tv_sec = timerQueue->time.tv_sec - curTime.tv_sec;
  1379.     timeout.tv_usec = timerQueue->time.tv_usec - curTime.tv_usec;
  1380.     if (timeout.tv_usec < 0) {
  1381.         timeout.tv_sec -= 1;
  1382.         timeout.tv_usec += 1000000;
  1383.     }
  1384.     }
  1385.     memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
  1386.     do {
  1387.     numFound = select(numFds, (SELECT_MASK *) readPtr,
  1388.         (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
  1389.         timeoutPtr);
  1390.     } while ((numFound == -1) && (errno == EINTR));
  1391.     if (numFound == 0) {
  1392.     goto checkTime;
  1393.     }
  1394.     goto checkFiles;
  1395. }
  1396.  
  1397. /*
  1398.  *--------------------------------------------------------------
  1399.  *
  1400.  * Tk_MainLoop --
  1401.  *
  1402.  *    Call Tk_DoOneEvent over and over again in an infinite
  1403.  *    loop as long as there exist any main windows.
  1404.  *
  1405.  * Results:
  1406.  *    None.
  1407.  *
  1408.  * Side effects:
  1409.  *    Arbitrary;  depends on handlers for events.
  1410.  *
  1411.  *--------------------------------------------------------------
  1412.  */
  1413.  
  1414. void
  1415. Tk_MainLoop()
  1416. {
  1417.     while (tk_NumMainWindows > 0) {
  1418.     Tk_DoOneEvent(0);
  1419.     }
  1420. }
  1421.  
  1422. /*
  1423.  *----------------------------------------------------------------------
  1424.  *
  1425.  * Tk_Sleep --
  1426.  *
  1427.  *    Delay execution for the specified number of milliseconds.
  1428.  *
  1429.  * Results:
  1430.  *    None.
  1431.  *
  1432.  * Side effects:
  1433.  *    Time passes.
  1434.  *
  1435.  *----------------------------------------------------------------------
  1436.  */
  1437.  
  1438. void
  1439. Tk_Sleep(ms)
  1440.     int ms;            /* Number of milliseconds to sleep. */
  1441. {
  1442.     static struct timeval delay;
  1443.  
  1444.     delay.tv_sec = ms/1000;
  1445.     delay.tv_usec = (ms%1000)*1000;
  1446.     (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
  1447.         (SELECT_MASK *) 0, &delay);
  1448. }
  1449.  
  1450. /*
  1451.  *----------------------------------------------------------------------
  1452.  *
  1453.  * Tk_RestrictEvents --
  1454.  *
  1455.  *    This procedure is used to globally restrict the set of events
  1456.  *    that will be dispatched.  The restriction is done by filtering
  1457.  *    all incoming X events through a procedure that determines
  1458.  *    whether they are to be processed immediately or deferred.
  1459.  *
  1460.  * Results:
  1461.  *    The return value is the previous restriction procedure in effect,
  1462.  *    if there was one, or NULL if there wasn't.
  1463.  *
  1464.  * Side effects:
  1465.  *    From now on, proc will be called to determine whether to process
  1466.  *    or defer each incoming X event.
  1467.  *
  1468.  *----------------------------------------------------------------------
  1469.  */
  1470.  
  1471. Tk_RestrictProc *
  1472. Tk_RestrictEvents(proc, arg, prevArgPtr)
  1473.     Tk_RestrictProc *proc;    /* X "if" procedure to call for each
  1474.                  * incoming event.  See "XIfEvent" doc.
  1475.                  * for details. */
  1476.     char *arg;            /* Arbitrary argument to pass to proc. */
  1477.     char **prevArgPtr;        /* Place to store information about previous
  1478.                  * argument. */
  1479. {
  1480.     Bool (*prev)  _ANSI_ARGS_((Display *display, XEvent *eventPtr, char *arg));
  1481.  
  1482.     prev = restrictProc;
  1483.     *prevArgPtr = restrictArg;
  1484.     restrictProc = proc;
  1485.     restrictArg = arg;
  1486.     return prev;
  1487. }
  1488.  
  1489. /*
  1490.  *--------------------------------------------------------------
  1491.  *
  1492.  * Tk_CreateFocusHandler --
  1493.  *
  1494.  *    Arrange for a procedure to be called whenever the focus
  1495.  *    enters or leaves a given window.
  1496.  *
  1497.  * Results:
  1498.  *    None.
  1499.  *
  1500.  * Side effects:
  1501.  *    After this procedure has been invoked, whenever tkwin gets
  1502.  *    or loses the input focus, proc will be called.  It should have
  1503.  *    the following structure:
  1504.  *
  1505.  *    void
  1506.  *    proc(clientData, gotFocus)
  1507.  *        ClientData clientData;
  1508.  *        int gotFocus;
  1509.  *    {
  1510.  *    }
  1511.  *
  1512.  *    The clientData argument to "proc" will be the same as the
  1513.  *    clientData argument to this procedure.  GotFocus will be
  1514.  *    1 if tkwin is getting the focus, and 0 if it's losing the
  1515.  *    focus.
  1516.  *
  1517.  *--------------------------------------------------------------
  1518.  */
  1519.  
  1520. void
  1521. Tk_CreateFocusHandler(tkwin, proc, clientData)
  1522.     Tk_Window tkwin;        /* Token for window. */
  1523.     Tk_FocusProc *proc;        /* Procedure to call when tkwin gets
  1524.                  * or loses the input focus. */
  1525.     ClientData clientData;    /* Arbitrary value to pass to proc. */
  1526. {
  1527.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1528.  
  1529.     winPtr->focusProc = proc;
  1530.     winPtr->focusData = clientData;
  1531. }
  1532.  
  1533. /*
  1534.  *--------------------------------------------------------------
  1535.  *
  1536.  * Tk_FocusCmd --
  1537.  *
  1538.  *    This procedure is invoked to process the "focus" Tcl command.
  1539.  *    See the user documentation for details on what it does.
  1540.  *
  1541.  * Results:
  1542.  *    A standard Tcl result.
  1543.  *
  1544.  * Side effects:
  1545.  *    See the user documentation.
  1546.  *
  1547.  *--------------------------------------------------------------
  1548.  */
  1549.  
  1550. int
  1551. Tk_FocusCmd(clientData, interp, argc, argv)
  1552.     ClientData clientData;    /* Main window associated with
  1553.                  * interpreter. */
  1554.     Tcl_Interp *interp;        /* Current interpreter. */
  1555.     int argc;            /* Number of arguments. */
  1556.     char **argv;        /* Argument strings. */
  1557. {
  1558.     Tk_Window tkwin = (Tk_Window) clientData;
  1559.     register TkWindow *winPtr = (TkWindow *) clientData;
  1560.     register TkWindow *newPtr;
  1561.  
  1562.     if (argc > 2) {
  1563.     Tcl_AppendResult(interp, "too many args: should be \"",
  1564.         argv[0], " ?window?\"", (char *) NULL);
  1565.     return TCL_ERROR;
  1566.     }
  1567.  
  1568.     if (argc == 1) {
  1569.     if (winPtr->mainPtr->focusPtr == NULL) {
  1570.         interp->result = "none";
  1571.     } else {
  1572.         interp->result = winPtr->mainPtr->focusPtr->pathName;
  1573.     }
  1574.     return TCL_OK;
  1575.     }
  1576.  
  1577.     if (strcmp(argv[1], "none") == 0) {
  1578.     newPtr = NULL;
  1579.     } else {
  1580.     newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
  1581.     if (newPtr == NULL) {
  1582.         return TCL_ERROR;
  1583.     }
  1584.     }
  1585.     if (winPtr->mainPtr->focusPtr == newPtr) {
  1586.     return TCL_OK;
  1587.     }
  1588.     if (winPtr == winPtr->dispPtr->mouseMainPtr) {
  1589.     if ((winPtr->mainPtr->focusPtr != NULL)
  1590.         && (winPtr->mainPtr->focusPtr->focusProc != NULL)) {
  1591.         (*winPtr->mainPtr->focusPtr->focusProc)(
  1592.             winPtr->mainPtr->focusPtr->focusData, 0);
  1593.     }
  1594.     winPtr->mainPtr->focusPtr = newPtr;
  1595.     if ((newPtr != NULL) && (newPtr->focusProc != NULL)) {
  1596.         (*newPtr->focusProc)(newPtr->focusData, 1);
  1597.     }
  1598.     } else {
  1599.     winPtr->mainPtr->focusPtr = newPtr;
  1600.     }
  1601.     return TCL_OK;
  1602. }
  1603.  
  1604. /*
  1605.  *--------------------------------------------------------------
  1606.  *
  1607.  * TkFocusEventProc --
  1608.  *
  1609.  *    This procedure is invoked whenever the pointer enters
  1610.  *    or leaves a top-level window.  It notifies the current
  1611.  *    owner of the focus, if any.
  1612.  *
  1613.  * Results:
  1614.  *    None.
  1615.  *
  1616.  * Side effects:
  1617.  *    None.
  1618.  *
  1619.  *--------------------------------------------------------------
  1620.  */
  1621.  
  1622. void
  1623. TkFocusEventProc(winPtr, eventPtr)
  1624.     register TkWindow *winPtr;    /* Top-level window just entered or left. */
  1625.     XEvent *eventPtr;        /* EnterWindow or LeaveWindow event. */
  1626. {
  1627.     register TkMainInfo *mainPtr;
  1628.     TkWindow *newMouseMainPtr = NULL;
  1629.  
  1630.     if (eventPtr->type == EnterNotify) {
  1631.     newMouseMainPtr = winPtr->mainPtr->winPtr;
  1632.     }
  1633.     if (winPtr->dispPtr->mouseMainPtr == newMouseMainPtr) {
  1634.     return;
  1635.     }
  1636.     if (winPtr->dispPtr->mouseMainPtr != NULL) {
  1637.     mainPtr = winPtr->dispPtr->mouseMainPtr->mainPtr;
  1638.     if ((mainPtr->focusPtr != NULL)
  1639.         && (mainPtr->focusPtr->focusProc != NULL)) {
  1640.         (*mainPtr->focusPtr->focusProc)(mainPtr->focusPtr->focusData, 0);
  1641.     }
  1642.     }
  1643.     winPtr->dispPtr->mouseMainPtr = newMouseMainPtr;
  1644.     if (newMouseMainPtr != NULL) {
  1645.     mainPtr = newMouseMainPtr->mainPtr;
  1646.     if ((mainPtr->focusPtr != NULL)
  1647.         && (mainPtr->focusPtr->focusProc != NULL)) {
  1648.         (*mainPtr->focusPtr->focusProc)(mainPtr->focusPtr->focusData, 1);
  1649.     }
  1650.     }
  1651. }
  1652.  
  1653. /*
  1654.  *--------------------------------------------------------------
  1655.  *
  1656.  * TkEventDeadWindow --
  1657.  *
  1658.  *    This procedure is invoked when it is determined that
  1659.  *    a window is dead.  It cleans up event-related information
  1660.  *    about the window.
  1661.  *
  1662.  * Results:
  1663.  *    None.
  1664.  *
  1665.  * Side effects:
  1666.  *    Various things get cleaned up and recycled.
  1667.  *
  1668.  *--------------------------------------------------------------
  1669.  */
  1670.  
  1671. void
  1672. TkEventDeadWindow(winPtr)
  1673.     TkWindow *winPtr;        /* Information about the window
  1674.                  * that is being deleted. */
  1675. {
  1676.     register TkEventHandler *handlerPtr;
  1677.     register InProgress *ipPtr;
  1678.  
  1679.     /*
  1680.      * While deleting all the handlers, be careful to check for
  1681.      * Tk_HandleEvent being about to process one of the deleted
  1682.      * handlers.  If it is, tell it to quit (all of the handlers
  1683.      * are being deleted).
  1684.      */
  1685.  
  1686.     while (winPtr->handlerList != NULL) {
  1687.     handlerPtr = winPtr->handlerList;
  1688.     winPtr->handlerList = handlerPtr->nextPtr;
  1689.     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  1690.         if (ipPtr->nextHandler == handlerPtr) {
  1691.         ipPtr->nextHandler = NULL;
  1692.         }
  1693.         if (ipPtr->winPtr == winPtr) {
  1694.         ipPtr->winPtr = None;
  1695.         }
  1696.     }
  1697.     ckfree((char *) handlerPtr);
  1698.     }
  1699.     if ((winPtr->mainPtr != NULL) && (winPtr->mainPtr->focusPtr == winPtr)) {
  1700.     winPtr->mainPtr->focusPtr = NULL;
  1701.     }
  1702. }
  1703.  
  1704. /*
  1705.  *----------------------------------------------------------------------
  1706.  *
  1707.  * TkCurrentTime --
  1708.  *
  1709.  *    Try to deduce the current time.  "Current time" means the time
  1710.  *    of the event that led to the current code being executed, which
  1711.  *    means the time in the most recently-nested invocation of
  1712.  *    Tk_HandleEvent.
  1713.  *
  1714.  * Results:
  1715.  *    The return value is the time from the current event, or
  1716.  *    CurrentTime if there is no current event or if the current
  1717.  *    event contains no time.
  1718.  *
  1719.  * Side effects:
  1720.  *    None.
  1721.  *
  1722.  *----------------------------------------------------------------------
  1723.  */
  1724.  
  1725. Time
  1726. TkCurrentTime(dispPtr)
  1727.     TkDisplay *dispPtr;        /* Display for which the time is desired. */
  1728. {
  1729.     register XEvent *eventPtr;
  1730.  
  1731.     if (pendingPtr == NULL) {
  1732.     return dispPtr->lastEventTime;
  1733.     }
  1734.     eventPtr = pendingPtr->eventPtr;
  1735.     switch (eventPtr->type) {
  1736.     case ButtonPress:
  1737.     case ButtonRelease:
  1738.         return eventPtr->xbutton.time;
  1739.     case KeyPress:
  1740.     case KeyRelease:
  1741.         return eventPtr->xkey.time;
  1742.     case MotionNotify:
  1743.         return eventPtr->xmotion.time;
  1744.     case EnterNotify:
  1745.     case LeaveNotify:
  1746.         return eventPtr->xcrossing.time;
  1747.     case PropertyNotify:
  1748.         return eventPtr->xproperty.time;
  1749.     }
  1750.     return dispPtr->lastEventTime;
  1751. }
  1752.